home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / BARNET / COMPILER / SATHER / !Sather / Library / Graphs / sa / ugraph_inc < prev    next >
Text File  |  1996-07-13  |  10KB  |  340 lines

  1. ---------------------------> Sather 1.1 source file <--------------------------
  2. -- Author: Benedict A. Gomes <gomes@tiramisu.ICSI.Berkeley.EDU>
  3. -- COPYRIGHT NOTICE: This code is provided WITHOUT ANY WARRANTY
  4. -- and is subject to the terms of the SATHER LIBRARY GENERAL PUBLIC
  5. -- LICENSE contained in the file: Sather/Doc/License of the
  6. -- Sather distribution. The license is also available from ICSI,
  7. -- 1947 Center St., Suite 600, Berkeley CA 94704, USA.
  8. -------------------------------------------------------------------
  9. partial class UGRAPH_INCL{NTP} < $UGRAPH{NTP} is
  10.    -- Partial class used to define useful routines in  undirected
  11.    -- graphs that are based on a core set of (undefined) routines
  12.    -- The core routines must be defined by a particular implementation
  13.    -- upon inclusion
  14.    private include COMPARE{NTP};
  15.    
  16.    -- ------------------- Stubs: Must redefine ------------
  17.    stub add_node: NTP;
  18.    stub add_node(n: NTP);
  19.    stub add_node(n: NTP):NTP;
  20.    stub connect(n1,n2: NTP); 
  21.    stub delete_node(n: NTP); 
  22.    stub disconnect(n1,n2: NTP); 
  23.    stub node!: NTP;
  24.    stub adjacent!(once n: NTP): NTP; 
  25.    stub copy: SAME;
  26.    stub create: SAME;
  27.    -- Some of the routines need to create a "fresh" graph.
  28.    
  29.    -- ------------------- Insertion -----------------------
  30.    connect(e: UEDGE{NTP}) is connect(e.first,e.second) end;
  31.  
  32.    disconnect(e: UEDGE{NTP}) is disconnect(e.first,e.second) end;
  33.  
  34.    -- ------------------- Access --------------------------
  35.    nodes: SET{NTP} is
  36.       res: SET{NTP};  loop res.insert(node!) end;  return res;
  37.    end;
  38.       
  39.    edges: SET{UEDGE{NTP}} is
  40.       res: SET{UEDGE{NTP}} := #;  loop res.insert(edge!) end;  return res;
  41.    end;
  42.    
  43.    adjacent(n: NTP): SET{NTP} is
  44.       res: SET{NTP} := #;  loop res.insert(adjacent!(n)) end;  return res;
  45.    end;
  46.    
  47.    reachable_from(n: NTP): SET{NTP} is
  48.       -- Returns the set of nodes reachable from "n"
  49.       res: SET{NTP};  loop res.insert(reachable_from!(n)) end; return res;
  50.    end;
  51.    
  52.    roots: SET{NTP} is
  53.       -- Returns a list of "representative" nodes from which the
  54.       -- whole graph is reachable. 
  55.       -- With inout args, also return a mapping from nodes to the
  56.       -- appropriate representative nodes (i.e. seen)
  57.       seen: FSET{NTP};
  58.       roots:SET{NTP};
  59.       loop n ::= node!; 
  60.      if ~seen.test(n) then  
  61.         roots.insert(n); 
  62.         loop  seen := seen.insert(reachable_from!(n));  end;
  63.      end;
  64.       end;
  65.       return roots;
  66.    end;
  67.  
  68.    node_depths(n: NTP,map:$MAP{NTP,INT}) is
  69.       -- map should be inout, but this will work for now
  70.       -- Do a bfs and return depths of each node
  71.       d ::= 1; loop map[bfs!(n)] := d; d := d + 1; end;
  72.    end;
  73.  
  74.    -- ------------------- Queries -------------------------
  75.    has_node(n: NTP): BOOL is
  76.       loop if elt_eq(n,node!) then return true end; end;
  77.       return false;
  78.    end;
  79.       
  80.    has_edge(first,second: NTP): BOOL is 
  81.       loop e ::= edge!;
  82.      if elt_eq(e.first,first) and elt_eq(e.second,second) then
  83.         return true;
  84.      end;
  85.       end;
  86.       return false;
  87.    end;
  88.  
  89.    has_edge(e: UEDGE{NTP}):BOOL is return has_edge(e.first,e.second) end;
  90.  
  91.    are_connected(n1,n2: NTP): BOOL is
  92.       -- Return true if there exists a path from n1 to n2
  93.       loop n: NTP := dfs!(n1);
  94.      if elt_eq(n,n2) then return true; end;
  95.       end;
  96.       return false;
  97.    end;
  98.    
  99.    is_empty: BOOL is return(n_nodes = 0) end;
  100.  
  101.    has(n: NTP): BOOL is return has_node(n) end;
  102.    
  103.    n_reachable_from(n: NTP): INT is 
  104.       i: INT := 0; loop discard ::= reachable_from!(n); i := i + 1;  end;
  105.       return i
  106.    end;
  107.  
  108.    n_edges: INT is
  109.       i: INT := 0; loop e ::= edge!; i := i + 1; end;
  110.       return i
  111.    end;
  112.    
  113.    n_nodes: INT is
  114.       i: INT := 0; loop e ::= node!; i := i + 1; end;
  115.       return i
  116.    end;      
  117.  
  118.    size: INT is return n_nodes end;
  119.    
  120.    n_adjacent(n: NTP): INT is
  121.       i: INT := 0; 
  122.       loop adj_n ::= adjacent!(n); i := i + 1; end;
  123.       return i;
  124.    end;
  125.  
  126.    -- ------------------- Cursor --------------------------
  127.    elt!: NTP is loop yield node! end; end;
  128.    
  129.    edge!: UEDGE{NTP} is
  130.       seen: FSET{NTP} := #;
  131.       loop n ::= node!;
  132.      seen := seen.insert(n);
  133.      loop 
  134.         neigh ::= adjacent!(n);
  135.         if ~seen.test(neigh) then   yield #UEDGE{NTP}(n,adjacent!(n));  end;
  136.         -- Avoid yielding edges twice, from both directions
  137.      end;
  138.       end;
  139.    end;
  140.    
  141.    filter_edge!(once pred: ROUT{UEDGE{NTP}}:BOOL):UEDGE{NTP} is
  142.       -- Return a set of edge tuples that are true for test "et"
  143.       loop e ::= edge!; if pred.call(e) then yield(e) end; end;
  144.    end;
  145.    
  146.    filter_node!(once pred: ROUT{NTP}:BOOL): NTP is
  147.       -- Return the set of all nodes in g that satisfy the node test "nt"
  148.       loop n ::= node!; if pred.call(n) then  yield n end end;
  149.    end;
  150.  
  151.    bfs!(once n: NTP): NTP is
  152.       -- Return all nodes reachable from "n" in bf order
  153.       seen: FSET{NTP} := #;
  154.       q: A_QUEUE{NTP} := #;
  155.       q.enq(n);
  156.       loop until!(q.is_empty);
  157.      current ::= q.remove;
  158.      yield current;
  159.      loop adjacent ::= adjacent!(current);
  160.         if ~seen.test(adjacent) then 
  161.            q.enq(adjacent); 
  162.            seen:=seen.insert(adjacent); 
  163.         end;
  164.      end;
  165.       end;
  166.    end;
  167.  
  168.    dfs!(once n: NTP): NTP is
  169.       -- Return all nodes reachable from "n" in df order
  170.       stack ::= #FLIST{NTP};  stack := stack.push(n);
  171.       seen  ::= #FSET{NTP};   seen := seen.insert(n);       
  172.       loop until!(stack.is_empty);
  173.      cur ::= stack.pop;     
  174.      yield cur;        -- Actual visit
  175.      loop neigh ::= adjacent!(cur);
  176.         if ~seen.test(neigh) then 
  177.            stack:=stack.push(neigh);
  178.            seen:=seen.insert(neigh);
  179.         end; -- else ( Adjacent has been seen before => backedge.) 
  180.      end;
  181.       end; -- Until stack is empty
  182.    end;
  183.  
  184.    reachable_from!(once n: NTP): NTP is
  185.       -- Returns successive nodes reachable from "n"
  186.       -- using dfs
  187.       loop yield dfs!(n) end;
  188.    end;
  189.      
  190.    -- ------------------- Comparison ----------------------
  191.    equals(g: $RO_UGRAPH{NTP}): BOOL is
  192.       -- Check that nodes and edges are the same
  193.       -- Very inefficient n^2 version - sort for nlogn version
  194.       if ~has_same_nodes(g) then return false end;
  195.       loop e ::= edge!; if ~g.has_edge(e) then return false end; end;
  196.       loop e ::= g.edge!; if ~has_edge(e) then return false end; end;
  197.       return(true);
  198.    end;
  199.  
  200.    has_same_nodes(g: $RO_UGRAPH{NTP}): BOOL is
  201.       if n_nodes /= g.n_nodes then return false end;
  202.       loop n ::= g.node!; if ~has_node(n) then return false end; end;
  203.       return true;
  204.    end;
  205.  
  206.    -- ------------------- Transformation ------------------
  207.    to_union(g: $UGRAPH{NTP}) is
  208.       loop add_node(g.node!) end;
  209.       loop connect(g.edge!) end;
  210.    end;
  211.  
  212.    to_difference(g: $UGRAPH{NTP}) is
  213.       loop e ::= edge!; 
  214.      if g.has_edge(e) then 
  215.         disconnect(e);
  216.         f ::= e.first; s ::= e.second;
  217.         if n_adjacent(f) = 0  then delete_node(f) end;
  218.         if n_adjacent(s) = 0 then delete_node(s) end;
  219.      end; 
  220.       end;
  221.    end;
  222.    
  223.    dfs_apply(n: NTP,prewk:ROUT{NTP},postwk:ROUT{UEDGE{NTP}}) is
  224.       -- Perform pre work before visiting a node and 
  225.       -- perform postwk on the way back up each edge
  226.       -- Recursive version of dfs (much simpler to code)
  227.       -- Here postwork is applied to *all* edges, including back edges
  228.       if void(postwk) then  dfs_apply(n,prewk);
  229.       else dfs_rec(#FSET{NTP},n,prewk,postwk);
  230.       end;
  231.    end;
  232.    
  233.    dfs_apply(n: NTP,wk:ROUT{NTP}) is
  234.       -- Apply the pre visit work "wk" to nodes in df order. Non recursive
  235.       stack: FLIST{NTP} := #;
  236.       seen ::= #FSET{NTP};
  237.       seen := seen.insert(n);       
  238.       stack := stack.push(n);
  239.       loop until!(stack.is_empty);
  240.      cur ::= stack.pop;     
  241.      wk.call(cur);
  242.      loop adjacent ::= adjacent!(cur);
  243.         if ~seen.test(adjacent) then 
  244.            stack:=stack.push(adjacent);
  245.            seen:=seen.insert(adjacent);
  246.         end; -- else ( Adjacent has been seen before => backedge.) 
  247.      end;
  248.       end; -- Until stack is empty
  249.    end; 
  250.    
  251.    to_transitive_closure is
  252.       -- Convert the graph to it's transitive closure
  253.       -- For a non-destructive version, first make a copy
  254.       loop 
  255.      u ::= node!;
  256.      loop v ::= node!;  if are_connected(u,v) then connect(u,v) end; end;
  257.       end;
  258.    end;
  259.  
  260.    delete_reflexive_edges is
  261.       -- Delete all reflexive edges from the graph
  262.       loop e ::= edge!;
  263.      if elt_eq(e.first,e.second) then disconnect(e) end;
  264.       end;
  265.    end;
  266.  
  267.    -- ------------------- Conversion ----------------------
  268.    str: STR is
  269.       return(str(bind(node_str(_))));
  270.    end;
  271.  
  272.    private node_str(n: NTP): STR is
  273.       if void(n) then return("void") end;
  274.       typecase n
  275.       when $STR then  return(n.str); else return("non-printable") end;
  276.    end;
  277.  
  278.    str(f: ROUT{NTP}:STR): STR is
  279.       -- Print out the graph using the bound routine "f"
  280.       -- for the nodes   
  281.       res ::= #FSTR("");
  282.       loop n ::= node!;
  283.      if void(n) then res := res + "void  : ";
  284.      else res := res + f.call(n)+" : "; end;
  285.      loop
  286.         nm: STR := f.call(adjacent!(n));
  287.         res := res + ",".separate!(nm);
  288.      end; -- All parents edges
  289.      res := res+"\n";        -- End of another row of edges
  290.       end; -- All graph nodes
  291.       return(res.str);
  292.    end;   
  293.  
  294.    -- ------------------- Basic Operations ----------------
  295.    union(g: $UGRAPH{NTP}): $UGRAPH{NTP} is
  296.       res: SAME := copy;
  297.       res.to_union(g);
  298.       return res;
  299.    end;
  300.  
  301.    difference(g:$UGRAPH{NTP}): $UGRAPH{NTP} is
  302.       res: SAME := copy; 
  303.       res.to_difference(g);
  304.       return res;
  305.    end;
  306.  
  307.    induced_subgraph(v: $SET{NTP}): $UGRAPH{NTP} is
  308.       -- Generate a subgraph which is induced by the edges "v".
  309.       res: SAME := #SAME;
  310.       loop n ::= node!;
  311.      res.add_node(n);
  312.      loop a ::= adjacent!(n);
  313.         if v.has(a) then res.connect(n,a) end;
  314.      end;
  315.       end;
  316.       return res;
  317.    end;
  318.  
  319.    -- ------------------- Implementation ------------------
  320.   private dfs_rec(seen:FSET{NTP},n:NTP,bef:ROUT{NTP},aft:ROUT{UEDGE{NTP}}) is
  321.       -- Recursive depth first search, when both pre and postwork
  322.       -- must be done. Seen holds the list of nodes already seen
  323.       seen := seen.insert(n);
  324.       bef.call(n);
  325.       neigh: $ARR{NTP} := adjacent(n);
  326.       ni: INT; nsz: INT := neigh.size;
  327.       loop until!(ni=nsz);
  328.      child::=neigh[ni];
  329.      bef.call(child);    -- Pre work on node
  330.      if ~seen.test(child) then
  331.         dfs_app_rec(seen,child,bef,aft); 
  332.         aft.call(#UEDGE{NTP}(n,child));    -- Post work on edge
  333.      end;
  334.      ni := ni+1;
  335.       end;
  336.    end;
  337.    
  338. end; -- class UGRAPH_ALG_INCL
  339. -------------------------------------------------------------------
  340.